#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) : ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::analyse() {
	programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::programme() {
// <programme> ::= debut <seqInst> fin FIN_FICHIER
	
	sauterSymCour("debut");
	seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::seqInst() {
// <seqInst> ::= <inst> ; { <inst> ; }

	do {
		inst();
		sauterSymCour(";");
	} while (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="si"   || ls.getSymCour()=="tantque" 
              || ls.getSymCour()=="repeter"    || ls.getSymCour()=="lire" || ls.getSymCour()=="ecrire" || ls.getSymCour()=="pour");
	// tant que le symbole courant est un debut possible d'instruction...
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::inst() {
// <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter> | <instLire> | <instEcrire>
    if (ls.getSymCour()=="lire")
        instLire();
    else if (ls.getSymCour()=="ecrire")
        instEcrire();
    else if (ls.getSymCour()=="si")
        instSi();
    else if (ls.getSymCour()=="tantque")
        instTq();
    else if (ls.getSymCour()=="repeter")
        instRepeter();
    else if (ls.getSymCour()=="<VARIABLE>")
	affectation();
    else if (ls.getSymCour()=="pour")
        instPour();
    else
        erreur("<inst>");
        
}

////////////////////////////////////////////////////////////////////////////////*
void LecteurPhraseAvecTable::affectation() {
// <affectation> ::= <variable> = <expression>
        
	testerSymCour("<VARIABLE>");
        ts.chercheAjoute(ls.getSymCour());
        ls.suivant();
	sauterSymCour("=");
	expression();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expression() {
//<expression> ::= <terme> { <opAdd> <terme> } 

	terme();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
		opAdd();
		terme();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::terme() {
//<terme> ::=  <facteur> { <opMult> <facteur> }    
    
    facteur();
    while(ls.getSymCour()=="*" || ls.getSymCour()=="/"){
        opMult();
        facteur();
    }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::facteur() {
// <facteur> ::= <entier>  |  <variable>  | <opUnaire> <expBoolEt> | ( <expBoolEt> )

	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>"){
                ts.chercheAjoute(ls.getSymCour());
                ls.suivant();
        }
	else if (ls.getSymCour()=="-" || ls.getSymCour()=="non") {
		opUnaire();
		expBoolEt();
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		expBoolEt();
		sauterSymCour(")");
	} else
		erreur("<facteur>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opAdd()
// <opAdd> ::= + | - 
{
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-")
		ls.suivant();
	else
		erreur("<opAdd>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opMult(){
// <opMult> ::=  *  | /
     if( ls.getSymCour()=="*" || ls.getSymCour()=="/" )
         ls.suivant();
     else 
         erreur("<opMult>");
}


///////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::expBoolOu() {
  //<exBoolOu>::= <expBoolEt> { <opOu> <expBoolEt> }
    expBoolEt();
    while (ls.getSymCour() == "ou") {
        opBoolOu();
        expBoolEt();
    }
}


////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::expBoolEt() {
  //<exBoolEt>::= <relation> { <opEt> <relation> }
    relation();
    while (ls.getSymCour() == "et") {
        opBoolEt();
        relation();
    }
}


////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opBoolOu() {
    //<opBoolOu>::= ou
    if (ls.getSymCour() == "ou") {
        ls.suivant();
    } else
        erreur("<opBoolOu>");
}


////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opBoolEt() {
    //<opBoolEt>::= et
    if (ls.getSymCour() == "et") {
        ls.suivant();
    } else
        erreur("<opBoolEt>");
}



////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::relation() {
  //<relation>::= <expression> { <opRel> <expression> }
    expression();
    while (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()==">" || ls.getSymCour()=="<=" || ls.getSymCour()==">=") {
        opRel();
        expression();
    }
}

///////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opRel() {
  //<opRel>::= == | != | < | <= | > | >=
    if (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()==">" || ls.getSymCour()=="<=" || ls.getSymCour()==">=")
        ls.suivant();
    else
        erreur("<opRel");
}

///////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opUnaire() {
  //<opUnaire>::= - | non
    if (ls.getSymCour()=="-" || ls.getSymCour()=="non")
        ls.suivant();
    else
        erreur("<opUnaire");
}

///////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instSi() {
  //<instSi>::= si ( <expBoolEt> ) <seqInst> { sinonsi ( <expBoolEt> ) <seqInst> } [ sinon <seqInst> ] finsi
    sauterSymCour("si");
    sauterSymCour("(");
    expBoolEt();
    sauterSymCour(")");
    seqInst();
    
    while (ls.getSymCour()=="sinonsi") {
        sauterSymCour("sinonsi");
        sauterSymCour("(");
        expBoolEt();
        sauterSymCour(")");
        seqInst();
    }
    
    if (ls.getSymCour()=="sinon") {
        sauterSymCour("sinon");
        seqInst();
    }
    
    sauterSymCour ("finsi");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instTq() {
  //<instTq>::= tantque ( <expBoolEt> ) <seqInst> fintantque
    sauterSymCour("tantque");
    sauterSymCour("(");
    expBoolEt();
    sauterSymCour(")");
    seqInst();
    sauterSymCour("fintantque");

}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instRepeter() {
  //<instRepeter>::= repeter <seqInst> jusqua ( <expBoolEt> )
    sauterSymCour("repeter");
    seqInst();
    sauterSymCour("jusqua");
    sauterSymCour("(");
    expBoolEt();
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instLire(){
  //<insLire>::= lire ( <variable> )
    sauterSymCour("lire");
    sauterSymCour("(");
    testerSymCour("<VARIABLE>");
    ts.chercheAjoute(ls.getSymCour());
    ls.suivant();
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instEcrire(){
  //<instEcrire>::= ecrire ( < expression> | <chaine> )  
    sauterSymCour("ecrire");
    sauterSymCour("(");
    if (ls.getSymCour()=="<CHAINE>"){
        testerSymCour("<CHAINE>");
        ts.chercheAjoute(ls.getSymCour());
        ls.suivant();
    }
    else 
        expression();
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instPour(){
  //<instPour>::= pour ( <affectation> ; <expBoolEt> ; <affectation>  ) <seqInst> finpour
    sauterSymCour("pour");
    sauterSymCour("(");
    affectation();
    sauterSymCour(";");
    expBoolEt();
    sauterSymCour(";");
    affectation();
    sauterSymCour(")");
    seqInst();
    sauterSymCour("finpour");
}





////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}
